;(function () {
  //我们不会使用函数类型去和其他类型（如对象类型）比较，因为这并没有意义，本文中只会对两个函数类型进行比较。来看示例，给出三个具有层级关系的类，分别代表动物、狗、柯基。

  class Animal {
    asPet() {}
  }
  class Dog extends Animal {
    bark() {}
  }
  class Corgi extends Dog {
    cute() {}
  }

  type DogFactory = (args: Dog) => Dog

  //对于 Animal、Dog、Corgi 这三个类，如果将它们分别可重复地放置在参数类型与返回值类型处（相当于排列组合），就可以得到以下这些函数签名类型
  function transformDogAndBark(dogFactory: DogFactory) {
    const dog = dogFactory(new Dog())
    dog.bark()
  }
  //如果一个值能够被赋值给某个类型的变量，那么可以认为这个值的类型为此变量类型的子类型。
  function makeDogBark(dog: Dog) {
    dog.bark()
  }
  //它在调用时只可能接受 Dog 类型或 Dog 类型的子类型，而不能接受 Dog 类型的父类型：
  makeDogBark(new Corgi()) // ok
  // makeDogBark(new Animal()) // no
  type AsFuncArgType<T> = (arg: T) => void
  type AsFuncReturnType<T> = (arg: unknown) => T

  // 1 成立：(T -> Corgi) ≼ (T -> Dog)
  type CheckReturnType = AsFuncReturnType<Corgi> extends AsFuncReturnType<Dog> ? 1 : 2

  // 2 不成立：(Dog -> T) ≼ (Animal -> T)
  type CheckArgType = AsFuncArgType<Dog> extends AsFuncArgType<Animal> ? 1 : 2

  function fn(dog: Dog) {
    dog.bark()
  }

  type CorgiFunc = (input: Corgi) => void
  type AnimalFunc = (input: Animal) => void

  const func1: CorgiFunc = fn
  // const func2: AnimalFunc = fn

  interface Array<T> {
    push(...items: T[]): number
  }
})()
